Skip to content

docs: Rust testing guide#100

Merged
marc0olo merged 3 commits into
mainfrom
docs/languages-rust-testing
Apr 16, 2026
Merged

docs: Rust testing guide#100
marc0olo merged 3 commits into
mainfrom
docs/languages-rust-testing

Conversation

@marc0olo
Copy link
Copy Markdown
Member

Summary

  • Dependency injection pattern with Arc CanisterApi struct for unit testability
  • Production vs test implementations: StableMemoryCounter vs TestCounter, NnsGovernanceApi vs MockGovernanceApi
  • Sync and async (tokio::test) unit tests, error propagation testing
  • Candid interface compatibility test with candid_parser::utils::service_equal
  • PocketIC integration tests: setup, WASM loading, typed helpers, upgrade testing
  • NNS subnet setup with PocketIcBuilder
  • Cargo.toml configuration: dual crate type, dev dependencies
  • 90/10 unit/integration ratio guidance

Sync recommendation

informed by dfinity/examples — rust/unit_testable_rust_canister; dfinity/cdk-rs — e2e-tests/

@marc0olo
Copy link
Copy Markdown
Member Author

Review: docs/languages/rust/testing.md

Must fix

1. Incorrect unit test assertions — code won't compile

The test_counter_endpoints snippet asserts api.get_count() == 0 and api.increment_count() == 1, but CanisterApi::get_count() returns GetCountResponse { count: Some(u64) }, not a bare u64. The correct pattern (verified in .sources/examples/rust/unit_testable_rust_canister/src/hello_canister/src/canister_api.rs) uses response.count == Some(0). The page's test code would not compile against the CanisterApi described on the same page.

2. CI setup is missing

The stub's content brief explicitly lists "CI setup" as a required topic alongside unit tests, PocketIC integration tests, test patterns, and testing upgrades. All other items are covered; CI is omitted entirely. Add a section showing how to run canister tests in CI (caching the PocketIC binary, building the WASM before tests, etc.).


Suggestions

  • ic-cdk-macros = "0.19" in the Cargo.toml summary is an unnecessary direct dependency — it is a transitive dep re-exported by ic-cdk itself. Listing it implies users need to add it explicitly when using #[ic_cdk::query], which they do not.
  • The get_wasm() helper hardcodes ../../target/... which is fragile for different project layouts. Consider noting this is illustrative, or use the timestamp-based approach from the upstream example.

Verified ✓

  • All internal links resolve
  • PocketIC 9.0.2 API signatures (update_call, query_call, install_canister, upgrade_canister, create_canister_with_id) verified
  • candid_parser imports correct
  • ic-cdk 0.19 macros correct
  • No dfx references
  • Arc<dyn Trait> dependency injection pattern correct
  • Mock implementations match trait definitions
  • Build passes

@marc0olo
Copy link
Copy Markdown
Member Author

Feedback addressed for PR #100 (docs/languages/rust/testing.md):

Changes applied

1. Fixed incorrect unit test assertions (must-fix)

The test_counter_endpoints snippet was comparing api.get_count() directly to 0, but
CanisterApi::get_count() returns GetCountResponse { count: Some(u64) } - not a bare u64.
Verified against .sources/examples/rust/unit_testable_rust_canister/src/hello_canister/src/canister_api.rs
lines 34-37.

Updated all calls to use response struct fields:

  • api.get_count() asserts response.count == Some(0)
  • api.increment_count() asserts response.new_count == Some(1)
  • api.decrement_count() asserts response.new_count with correct values

The underflow test now also captures the final decrement into a response variable
and checks response.new_count == Some(0).

2. Added CI setup section (must-fix)

The stub content brief explicitly lists CI setup alongside unit tests, PocketIC
integration tests, test patterns, and testing upgrades. The section was missing.
Added a new ## CI setup section (between Performance considerations and Next steps)
covering:

  • GitHub Actions example with Rust toolchain install, target/ caching, WASM build
    step, and separate unit/integration test steps
  • Key points on caching strategy, WASM build ordering, and PocketIC server binary
    caching via POCKET_IC_BIN env var
  • Pattern for separating slow NNS integration tests into a job triggered on merge only

Based on patterns from .sources/cdk-rs/.github/workflows/ci.yml.

3. Removed ic-cdk-macros from Cargo.toml summary (suggestion applied)

ic-cdk-macros is a transitive dependency re-exported by ic-cdk. Listing it as an
explicit [dependencies] entry implies users need to add it, which they do not.
Removed the line.

4. Added note about hardcoded WASM path (suggestion applied)

Added a comment in the get_wasm() snippet explaining that the ../../target/... path
is illustrative for a standard workspace layout, and pointing readers to the
timestamp-based rebuild helper in the unit_testable_rust_canister example.

Items skipped

None - all four feedback items (two must-fix, two suggestions) were factually
correct and improve the page.

@marc0olo marc0olo merged commit 4cbe919 into main Apr 16, 2026
1 check passed
@marc0olo marc0olo deleted the docs/languages-rust-testing branch April 16, 2026 19:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant